﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Runtime.Serialization;

namespace PitBull.Collection
{
    [Serializable]
    [DataContract]
    public class TyskenFastCollection<T>: IEnumerable<T> where T : ITyskenCollection<T>, new()
    {
        #region Members

        [DataMember]
        private bool _IsChanged;
        [DataMember]
        [NonSerialized]
        private HashSet<T> _items = new HashSet<T>();
        [DataMember]
        [NonSerialized]
        private HashSet<T> _originalItems;

        [field: NonSerialized]
        public event EventHandler ItemModified;
        [field: NonSerialized]
        public event EventHandler<BeforeItemDeletetedEventArgs> BeforeItemDeleted;
        [field: NonSerialized]
        public event EventHandler StatesModified;

        [NonSerialized]
        //Flagga som som används för att hålla redan på om Collctionen håller på att hantera IsChange.
        private bool _isSettingCurrentValue;

        #endregion

        #region Properties

        public TyskenFastCollection<T> AddedItems
        {
            get
            {
                if (_originalItems == null)
                    throw new Exception(GetContainingType().ToString() + " Missing SetCurrentValueAsOriginal. OBS! Även på nya tomma listor");

                TyskenFastCollection<T> returnList = new TyskenFastCollection<T>();
                
                foreach (T itm in _items.Where(c => !_originalItems.Contains(c)))
                    returnList.Add(itm);

                //Returnerar Collection
                return returnList;
            }
        }

        public TyskenFastCollection<T> DeletedItems
        {
            get
            {
                if (_originalItems == null)
                    throw new Exception(GetContainingType().ToString() + " Missing SetCurrentValueAsOriginal. OBS! Även på nya tomma listor");

                TyskenFastCollection<T> returnList = new TyskenFastCollection<T>();

                foreach (T itm in _originalItems.Where(c => !_items.Contains(c)))
                    returnList.Add(itm);

                //Returnerar Collection
                return returnList;
            }
        }

        public TyskenFastCollection<T> ModifiedItems
        {
            get
            {
                if (_originalItems == null)
                    throw new Exception(GetContainingType().ToString() + " Missing SetCurrentValueAsOriginal. OBS! Även på nya tomma listor");

                TyskenFastCollection<T> returnList = new TyskenFastCollection<T>();

                foreach (T itm in _items.Where(c => _originalItems.Contains(c) && c.IsChanged))
                    returnList.Add(itm);
                
                //Returnerar Collection
                return returnList;
            }
        }

        

        #endregion


        #region Methods

        public void SetCurrentValueAsOriginal()
        {

            _isSettingCurrentValue = true;

            if (_originalItems == null)
                _originalItems = new HashSet<T>();

            _originalItems.Clear();

            foreach (T item in _items)
                _originalItems.Add((T)ObjectHandler.CopyObject(item));


            _isSettingCurrentValue = true;

        }

        public Type GetContainingType()
        {
            return typeof(T);
        }

        #endregion

        #region ITyskenCollection

        /// <summary>
        /// Property som används för att fråga Kollektionen om någonting har förändrats.
        /// </summary>
        public bool IsChanged
        {
            get
            {
                if (_originalItems == null)
                    return true;
                //För att undvika crash då kör setCurrentValueAsOriginal
                if (_isSettingCurrentValue)
                    return false;

                if (AddedItems.Count > 0)
                    return true;
                else if (DeletedItems.Count > 0)
                    return true;
                else if (ModifiedItems.Count > 0)
                    return true;
                return false;
            }
            set
            {
                if (!value)
                    SetCurrentValueAsOriginal();
                else
                    throw new Exception("Set ischanged = true?");
            }

        }
        
        public bool Equals(T o)
        {
            TyskenFastCollection<T> tempCollection;

            if ((tempCollection = o as TyskenFastCollection<T>) != null)
            {
                if (tempCollection._items.Count == this._items.Count)
                {
                    for (int i = 0; i < this._items.Count; i++)
                    {
                        if (!object.Equals(tempCollection._items.ElementAt(i), this._items.ElementAt(i)))
                            return false;
                    }
                    return true;
                }
            }

            return base.Equals(o);
        }

        public void Add(T item)
        {
            if (item is IEntityCollectionWithEvent<T>)
                (item as IEntityCollectionWithEvent<T>).PropertyChanged += new PropertyChangedEventHandler(itm_PropertyChanged);
            
            this._items.Add(item);
            
                if (ListChanged != null)
                    ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemAdded, _items.ToList<T>().IndexOf(item)));
        }

        public T AddNew()
        {
            T temp = new T();
            _items.Add(temp);
            return temp;
        }

        public int Count
        {
            get { return _items.Count; }
        }

        void itm_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
                if (ListChanged != null)
                    ListChanged(sender, new ListChangedEventArgs(ListChangedType.ItemChanged, _items.ToList<T>().IndexOf((T)sender)));
        }

        #endregion

        #region Events



        #endregion

        #region ICancelAddNew

        public void CancelNew(int itemIndex)
        {
            throw new NotImplementedException();
        }

        public void EndNew(int itemIndex)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IEnumerator<T>

        public IEnumerator<T> GetEnumerator()
        {
            return _items.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _items.GetEnumerator();
        }

        #endregion

        //#region IBindingList

        //public void AddIndex(PropertyDescriptor property)
        //{
        //    throw new NotImplementedException();
        //}

        //public object AddNew()
        //{
        //    T temp = new T();

        //    _items.Add(temp);

        //    return temp;
        //}

        //public bool AllowEdit
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //public bool AllowNew
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //public bool AllowRemove
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //public void ApplySort(PropertyDescriptor property, ListSortDirection direction)
        //{
        //    throw new NotImplementedException();
        //}

        //public int Find(PropertyDescriptor property, object key)
        //{
        //    throw new NotImplementedException();
        //}

        //public bool IsSorted
        //{
        //    get { throw new NotImplementedException(); }
        //}

        public event ListChangedEventHandler ListChanged;

        //public void RemoveIndex(PropertyDescriptor property)
        //{
        //    throw new NotImplementedException();
        //}

        //public void RemoveSort()
        //{
        //    throw new NotImplementedException();
        //}

        //public ListSortDirection SortDirection
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //public PropertyDescriptor SortProperty
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //public bool SupportsChangeNotification
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //public bool SupportsSearching
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //public bool SupportsSorting
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //public int Add(object value)
        //{
        //    if (value is T)
        //    {
        //        T tempNewValue = (T)value;
        //        _items.Add(tempNewValue);

        //        return _items.ToList().IndexOf(tempNewValue);
        //    }

        //    return -1;
        //}

        //public void Clear()
        //{
        //    _items.Clear();
        //}

        //public bool Contains(object value)
        //{
        //    if (value is T)
        //    {
        //        T tempValue = (T)value;

        //        return _items.Contains(tempValue);
        //    }
        //    else
        //        return false;
        //}

        //public int IndexOf(object value)
        //{
        //    throw new NotImplementedException();
        //}

        //public void Insert(int index, object value)
        //{
        //    throw new NotImplementedException();
        //}

        //public bool IsFixedSize
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //public bool IsReadOnly
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //public void Remove(object value)
        //{
        //    throw new NotImplementedException();
        //}

        //public void RemoveAt(int index)
        //{
        //    throw new NotImplementedException();
        //}

        //public object this[int index]
        //{
        //    get
        //    {
        //        throw new NotImplementedException();
        //    }
        //    set
        //    {
        //        throw new NotImplementedException();
        //    }
        //}

        //public void CopyTo(Array array, int index)
        //{
        //    throw new NotImplementedException();
        //}

        //public int Count
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //public bool IsSynchronized
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //public object SyncRoot
        //{
        //    get { throw new NotImplementedException(); }
        //}

        //#endregion


    }



    
}
